package com.hmy.finance.common.easyexcel.pojo.readlistener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.hmy.finance.common.easyexcel.exception.ExcelBatchDataHandlerException;
import com.hmy.finance.common.easyexcel.pojo.importbeans.ImportErrorCellData;
import com.hmy.finance.common.easyexcel.pojo.importbeans.ImportSingleData;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Objects;


@Data
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
public class DefaultReadListener<T extends ImportSingleData> extends AbstractReadListener<T> {

    /**
     * 是否开启批次处理逻辑
     * 默认不开启;
     * -不开启，走全量返回数据逻辑，接到所有数据后自行处理;
     * -开启，不再返回全量数据逻辑，自定义类实现BatchDataHandlerInterface接口，进行批处理逻辑;
     */
    private Boolean enableBatchHandler = Boolean.FALSE;

    /**
     * 批次处理逻辑类
     */
    private BatchDataHandlerInterface batchDataHandler = null;

    /**
     * 每隔5条读取一次，可以配置,默认是10;
     */
    private static final int BATCH_COUNT = 5;

    /**
     * 一次缓存的数据
     */
    private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    /**
     * 一次缓存的异常数据保存
     */
    private List<ImportErrorCellData> cacheErrorCellDatas = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);


    @Override
    public void invoke(T data, AnalysisContext context) {
        Integer currentRowNum = context.readRowHolder().getRowIndex();
        /*对表头进行过滤*/
        if (currentRowNum < this.getStartRowNum()) {
            return;
        }

        data.setCurrentRowNum(currentRowNum + getStartRowNum());//客户excel上从1开始，需要+StartRowNum
        /*根据是否批次执行来处理*/
        if (Boolean.TRUE.equals(enableBatchHandler)) {
            cachedDataList.add(data);
            batchDataHandler();
        } else {
            this.getTotalDataList().add(data);
        }

    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        /*所有数据读取后执行的操作*/
        doLastBatchDataHandler();//分批最后可能还剩几个，需要执行一次批次处理逻辑，防止数据丢失;
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) {
        if (exception instanceof ExcelBatchDataHandlerException) {
            throw new RuntimeException(exception);
        }

        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            ImportErrorCellData importErrorCellData = ImportErrorCellData.builder()
                    .currentRowNum(excelDataConvertException.getRowIndex() + getStartRowNum())//实际的数据行需要加上起始头占用的行数
                    .errorMsg("格式转换错误").cellData(excelDataConvertException.getCellData()).build();

            if (Boolean.TRUE.equals(enableBatchHandler)) {
                this.cacheErrorCellDatas.add(importErrorCellData);
                batchDataHandler();
            } else {
                this.getTotalErrorCellDatas().add(importErrorCellData);
            }
        }
        /*根据实际扩展其他异常类，暂时想不到。*/
        log.info("解析失败，继续解析下一行:{}", exception.getMessage());
    }

    /**
     * 这里会一行行的返回头
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        log.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
    }

    /**
     * 处理批次数据，调用实现类逻辑。暂时不需要，后面扩展利用
     */
    public void batchDataHandler(Class<? extends BatchDataHandlerInterface> clazz, List<T> batchData) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        BatchDataHandlerInterface instance = clazz.getDeclaredConstructor().newInstance();
        Method method = clazz.getMethod("batchDataHandler", List.class);
        method.invoke(instance, batchData);
    }

    private void batchDataHandler() {
        if (cachedDataList.size() + cacheErrorCellDatas.size() >= BATCH_COUNT) {
            if (Objects.nonNull(batchDataHandler)) {
                batchDataHandler.batchDataHandler(cachedDataList, cacheErrorCellDatas);
            } else {
                throw new ExcelBatchDataHandlerException("batchDataHandler is null,分批处理情况下必须指定BatchDataHandlerInterface的实现");
            }
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            cacheErrorCellDatas = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    private void doLastBatchDataHandler() {
        if (Objects.nonNull(batchDataHandler)) {
            batchDataHandler.batchDataHandler(cachedDataList, cacheErrorCellDatas);
        } else {
            throw new ExcelBatchDataHandlerException("batchDataHandler is null,分批处理情况下必须指定BatchDataHandlerInterface的实现");
        }
        cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        cacheErrorCellDatas = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    }

}
